package cac.common;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import cn.hutool.core.util.XmlUtil;

/**   
* @ClassName: XmlReadUtil   
* @Description:	xml文件内容读取工具类
* 				一、基于org.w3c.dom，以及Hutool的XML工具XmlUtil，
* 				二、JDK目前已经封装有XML解析和构建工具：w3c dom，但是其API操作比较繁琐，Hutool的XmlUtil对w3c dom进行了简单工具化封装
* 				三、如果XML操作较复杂，依旧推荐使用Dom4j
* 				四、本工具类针对的xml文档格式：数据库表名→xml文档元素节点，表字段→元素节点属性值。如下所示：
* 					<root>
* 						<AIKDocument aoType="AODoc" isKey="1">
* 							<AIKChanges>
* 								<AIKChange date="20200611" modifyContent="修订"/>
* 								<AIKChange date="20200610" modifyContent="新增"/>
* 							</AIKChanges>
* 							<AIKsequences>
* 								<AIKsequence sequenceNum="00" sequenceName="预装"/>
* 								<AIKsequence sequenceNum="05" sequenceName="准备"/>
* 							</AIKsequences>
* 						</AIKsequences>
* 					</root>		
* 				五：该工具类使用方式：
* 					1、获得xml文件输入流，new FileInputStream(xmlPath);
* 					2、构造该工具类使用对象，new XmlReadUtil(xmlStream);
* 					3、使用相应方法，完成xml文档的解析，getAttributesByTagName(String tagName);
* 					4、使用完成后，关闭xml文件输入流，xmlStream.close();;			
* @author: 杨铁军
* @date: 2022年6月28日 上午11:09:25
*/
public class XmlReadUtil {

	// XML文档对象
	private Document doc;
	
	// XML文档元素节点的根节点对象
	private Element rootElement;
	
	/**   
	* @Title:  XmlReadUtil   
	* @Description:  参数构造，通过XML文件输入流构造XML文档对象与文档元素根节点对象   
	* @param: in XML文件输入流 
	*/ 
	public XmlReadUtil(InputStream in) {
		this.doc = XmlUtil.readXML(in);
		this.rootElement = XmlUtil.getRootElement(doc);
	}
	
	
	/**   
	* @Title: getAttributesByTagName   
	* @Description: 获取xml文件指定元素节点的属性值，因为可能存在多个同名元素节点，所以返回List     
	* @param tagName 指定的元素节点名
	* @return ArrayList<Map<String,String>>        
	*/
	public ArrayList<Map<String, String>> getAttributesByTagName(String tagName){
		// 方法返回的List
		ArrayList<Map<String, String>> attributesList = new ArrayList<>();
		
		// 获取所有指定的元素节点
		NodeList nodeList = this.rootElement.getElementsByTagName(tagName);
		
		// 遍历元素节点，将属性值转为Map
		for (int i = 0; i < nodeList.getLength(); i++) {
			
			NamedNodeMap nodeMap = nodeList.item(i).getAttributes();
		
			Map<String, String> AttributesMap = new HashMap<>();
			
			for (int j=0;j<nodeMap.getLength();j++) {
				String key = nodeMap.item(j).getNodeName();
				String value = nodeMap.item(j).getNodeValue();
				
				AttributesMap.put(key, value);
			}
			
			attributesList.add(AttributesMap);
		}
		
		return attributesList;
	}
	
	
	/**   
	* @Title: getAttributesByTagName   
	* @Description: 获取xml文件指定元素节点的属性值，并将指定父节点的指定属性一并添加到节点里
	* @param parentNodeNameArray 父节点名称数组，示例：new String[] {"AIKDocument","AIKsequence"}
	* @param parentAttributeKeyArray 父节点属性参数数组，示例：new String[] {"aoType","sequenceNum"}
	* @param tagName 指定的元素节点名
	* @return ArrayList<Map<String,String>>        
	*/
	public ArrayList<Map<String, String>> getAttributesByTagName(String[] parentNodeNameArray,String[] parentAttributeKeyArray,String tagName){
		// 方法返回的List
		ArrayList<Map<String, String>> attributesList = new ArrayList<>();
		
		// 获取所有指定的元素节点
		NodeList nodeList = this.rootElement.getElementsByTagName(tagName);
		
		// 遍历元素节点，将属性值转为Map，同时将父节点的属性值加入
		for (int i = 0; i < nodeList.getLength(); i++) {

			// 获取当前元素节点的属性值		
			Map<String, String> AttributesMap = new HashMap<>();
			
			Node node = nodeList.item(i);
			NamedNodeMap nodeMap = node.getAttributes();
			for (int j=0;j<nodeMap.getLength();j++) {
				String key = nodeMap.item(j).getNodeName();
				String value = nodeMap.item(j).getNodeValue();
				
				AttributesMap.put(key, value);
			}
			
			// 将父节点的属性值加入			
			for (String parentNodeName: parentNodeNameArray) {	
				
				Node parentNode = node.getParentNode();
				
				// 循环遍历，找到当前节点的父节点
				while (!parentNodeName.equals(parentNode.getNodeName())) {

					parentNode = parentNode.getParentNode();
					
				}
				
				// 找到父节点后，将父节点的属性值加入
				for (String parentAttribute : parentAttributeKeyArray) {
					
					NamedNodeMap parentNodeMap = parentNode.getAttributes();
					
					for (int j=0;j<parentNodeMap.getLength();j++) {
						
						String key = parentNodeMap.item(j).getNodeName();
						
						if (key.equals(parentAttribute)) {
							
							String value = parentNodeMap.item(j).getNodeValue();
							
							AttributesMap.put(key, value);
						}
					}
				}
			}
			
			attributesList.add(AttributesMap);
		}
		
		return attributesList;
	}
	
}
